/**
 * @file mf_fifo.c
 * @author Mayfly Zhang (zhangquzhi123456@163.com)
 * @brief 定义操作FIFO的函数。支持结构化数据单元
 * @version 0.0
 * @date 2021-03-29
 *
 * @copyright Copyright (c) 2021
 *
 */

#include "mf_fifo.h"

/**
 * @brief   初始化FIFO
 *
 * @param fifo      指向待初始化的FIFO的指针
 * @param data      指向FIFO数据缓冲区的指针
 * @param unit      FIFO缓冲区每个数据成员的大小
 * @param size      FIFO数据缓冲区成员数目
 * @return u8       MF_FALSE 失败；MF_TRUE 成功
 */
u8 fifo_init(FIFO_t *fifo, void * const data, u16 unit, u16 size)
{
    if (fifo == MF_NULL)
        return MF_FALSE;
    if (data == MF_NULL)
        return MF_FALSE;
    if (unit == 0U)
        return MF_FALSE;
    if (size == 0U)
        return MF_FALSE;

    fifo->data = data;
    fifo->head = fifo->tail = fifo->len = 0U;
    fifo->unit = unit;
    fifo->size = size;

    return MF_TRUE;
}

/**
 * @brief   写一个数据到FIFO
 *
 * @param fifo      指向待写入数据的FIFO
 * @param data      写入的数据
 * @return u8       MF_FALSE 失败；MF_TRUE 成功
 */
u8 fifo_write(FIFO_t *fifo, void const * const data)
{
    u8 *f_data, *d_data;
    u16 i;

    if (!FIFO_IS_EXIST(fifo))
        return MF_FALSE;
    if (FIFO_IS_FULL(fifo))
        return MF_FALSE;

    if (fifo->unit == 1U)
    {
        f_data = (u8 *)fifo->data + fifo->tail;
        *f_data = *((u8 *)data);
    }
    else
    {
        f_data = (u8 *)fifo->data + fifo->tail*fifo->unit;
        d_data = (u8 *)data;
        for (i = 0U; i < fifo->unit; i++)
        {
            *(f_data + i) = *(d_data + i);
        }
    }
    fifo->len++;

    fifo->tail++;
    if(fifo->tail == fifo->size)
       fifo->tail = 0U;

    return MF_TRUE;
}

/**
 * @brief   从FIFO读出一个数据
 *
 * @param fifo      指向待读出数据的FIFO指针
 * @return void *   FIFO_NULL 失败；其他，成功
 */
void * fifo_read(FIFO_t *fifo)
{
    u8 *f_data;

    if (!FIFO_IS_EXIST(fifo))
        return MF_NULL;
    if (FIFO_IS_EMPTY(fifo))
        return MF_NULL;

    f_data = ((u8 *)fifo->data + fifo->head*fifo->unit);
    fifo->len--;

    fifo->head++;
    if(fifo->head == fifo->size)
       fifo->head = 0U;

    return f_data;
}

/**
 * @brief   删除FIFO
 *
 * @param fifo      指向待删除FIFO的指针
 * @return u8       MF_FALSE 失败；MF_TRUE 成功
 */
u8 fifo_delete(FIFO_t *fifo)
{
    if (!FIFO_IS_EXIST(fifo))
        return MF_FALSE;

    fifo->data = MF_NULL;
    fifo->head = fifo->tail = fifo->unit = fifo->size = fifo->len = 0U;

    return MF_TRUE;
}
